﻿using System;
using System.Net;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.IO;
using System.Linq;
namespace Deliver
{
    // State object for receiving data from remote device.
    public class StateObject
    {
        // Client socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 1024;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
    }

    public class AsynchronousClient
    {
        // ManualResetEvent instances signal completion.
        private ManualResetEvent connectDone =
            new ManualResetEvent(false);
        private ManualResetEvent sendDone =
            new ManualResetEvent(false);
        private ManualResetEvent receiveDone =
            new ManualResetEvent(false);

        private ManualResetEvent receiveResult = new ManualResetEvent(false);
        // The response from the remote device.
        private String response = String.Empty;

        private bool StartClient(object command,out string msg)
        {
            msg = "";
            if (command == null)
            {
                return false;
            }
            Command c = command as Command;
            Socket client = null;
            // Connect to a remote device.
            try
            {

                // Establish the remote endpoint for the socket.
                // The name of the 
                // remote device is "host.contoso.com"
                IPAddress ipAddress = IPAddress.Parse(c.ServerIp);

                IPEndPoint remoteEP = new IPEndPoint(ipAddress, c.Port);
                // Create a TCP/IP socket.
                client = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream, ProtocolType.Tcp);
                // Connect to the remote endpoint.
                client.Connect(remoteEP);
                // Send test data to the remote device.
                var sendCmd = new { Id = c.Id, LocalPath = c.ServerPath, Count = c.Count, Type = c.Type };
                Send(client, "<START>" + Newtonsoft.Json.JsonConvert.SerializeObject(sendCmd) + "<EOF>");
                // Receive the response from the remote device.
                Receive(client);
                // Write the response to the console.
                Console.WriteLine("从第 {0} 个字节开始传输", response);
                if (sendCmd.Type == "copy")
                {
                    if (response == "true")
                    {
                        //要同步的一端已经完成了同步
                        LogYuMin.LogWriter.GetWriter(LogYuMin.LogFile.Log).Write("文件 ServerPath:" + c.ServerPath + " 结果:同步成功");

                        return true;
                    }
                }
                Send(client, c.Data);
                Receive(client);
                if (response == "true")
                {
                    LogYuMin.LogWriter.GetWriter(LogYuMin.LogFile.Log).Write("文件 ServerPath:" + c.ServerPath + " 结果:同步成功");
                    return true;
                }
                else
                {
                    LogYuMin.LogWriter.GetWriter(LogYuMin.LogFile.Log).Write("文件 ServerPath:" + c.ServerPath + "同步失败");
                    return false;
                }

            }
            catch (FileNotFoundException e)
            {
                LogYuMin.LogWriter.GetWriter(LogYuMin.LogFile.error).Write(GetType(), "StartClient", LogYuMin.LogStates.ERROR, e);
                msg = e.Message;
                return false;
            }
            catch (Exception e)
            {
                LogYuMin.LogWriter.GetWriter(LogYuMin.LogFile.error).Write(GetType(), "StartClient", LogYuMin.LogStates.ERROR, e);
                msg = e.Message;
                return false;
            }
            finally
            {
                try
                {
                    client.Disconnect(false);
                }
                catch
                {
                }
            }
        }

        private void Receive(Socket client)
        {

            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = client;
            // Begin receiving the data from the remote device.
            int bytesRead = client.Receive(state.buffer);
            response = Encoding.GetEncoding("gbk").GetString(state.buffer, 0, bytesRead);
            Console.WriteLine("传回数据:" + response);
        }


        private void Send(Socket client, String data)
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.GetEncoding("gbk").GetBytes(data);
            // Begin sending the data to the remote device.
            //client.BeginSend(byteData, 0, byteData.Length, 0,
            //    new AsyncCallback(SendCallback), client);
            Send(client, byteData);
            sendDone.Set();
        }

        private void Send(Socket client, string path, long startIndex)
        {
            FileStream fs = null;
            byte[] buffer = new byte[102400];
            FileInfo sendFile = new FileInfo(path);

            using (fs = sendFile.OpenRead())
            {
                fs.Position = startIndex;
                int tmpcount = 0;
                while ((tmpcount = fs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    if (tmpcount != buffer.Length)
                    {
                        byte[] endbuffer = new byte[tmpcount];
                        Array.Copy(buffer, endbuffer, tmpcount);
                        Send(client, endbuffer);
                        break;
                    }
                    Send(client, buffer);
                }
            }
        }

        private void Send(Socket client, byte[] data)
        {
            client.Send(data);
        }


        /// <summary>
        /// 封装一个传送
        /// </summary>
        /// <param name="c">传送命令实体</param>
        public static bool StartTranCommand(byte[] data, string serverPath,out string msg)
        {
            msg = string.Empty;
            AsynchronousClient tt = new AsynchronousClient();
            string fileServer = System.Configuration.ConfigurationManager.AppSettings["FileServer"];
            foreach (var c in fileServer.Split('|'))
            {
                var t = c.Split(',');
                var server = new { ip = t[0], port = int.Parse(t[1]) };
                Command command = new Command();
                command.Id = Guid.NewGuid().ToString();
                command.Count = data.Length;
                command.CTime = DateTime.Now;
                command.Data = data;
                command.Port = server.port;
                command.ServerIp = server.ip;
                command.ServerPath = serverPath;
                command.Type = "copy";
                if (!tt.StartClient(command,out msg))
                {
                    return false;
                }
            }
            return true;
        }

    }
}